#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
检测相关API路由模块
提供目标检测、模型管理和检测配置等功能的RESTful接口
"""

from flask import Blueprint, request, jsonify, current_app
from flask_cors import CORS
import logging
import base64
import numpy as np
from PIL import Image
import io
import time
import os

# 导入认证装饰器
from .auth import token_required

# 导入新的检测服务
from core.detection.detection_service import DetectionService

# 导入配置管理
from config import get_config, set_config

# 创建Blueprint

detections_bp = Blueprint('detections', __name__, url_prefix='/api/detections')

# 配置CORS
CORS(detections_bp, supports_credentials=True)

# 设置日志
logger = logging.getLogger('detection_api')

# 创建检测服务实例
_detection_service = None

def get_detection_service():
    """获取检测服务实例（单例模式）"""
    global _detection_service
    if _detection_service is None:
        _detection_service = DetectionService()
    return _detection_service

@detections_bp.before_app_first_request
def initialize_detection_service():
    """在应用首次请求时初始化检测服务"""
    try:
        service = get_detection_service()
        logger.info("检测服务已初始化")
    except Exception as e:
        logger.error(f"初始化检测服务失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")

# 健康检查接口 - 检测服务状态
@detections_bp.route('/health', methods=['GET'])
def detection_health_check():
    """检测服务健康检查接口"""
    try:
        service = get_detection_service()
        status = service.get_service_status()
        # 提取需要的信息
        active_model = None
        device = None
        loaded_models = []
        
        if 'active_engine' in status and status['active_engine'] and 'model_info' in status['active_engine']:
            active_model_info = status['active_engine']['model_info']
            if active_model_info:
                active_model = active_model_info.get('model_path')
                device = active_model_info.get('device')
        
        if 'engines' in status:
            loaded_models = status['engines']
        
        return jsonify({
            'status': 'healthy',
            'service': 'detection-service',
            'active_model': active_model,
            'device': device,
            'loaded_models': loaded_models,
            'timestamp': time.time()
        })
    except Exception as e:
        logger.error(f"检测服务健康检查失败: {str(e)}")
        return jsonify({
            'status': 'unhealthy',
            'error': str(e),
            'timestamp': time.time()
        }), 500

# 图像检测接口 - 支持base64编码的图像
@detections_bp.route('/image', methods=['POST'])
def detect_image():
    """
    图像目标检测接口
    接收base64编码的图像，返回检测结果
    """
    try:
        data = request.json
        if not data or 'image' not in data:
            return jsonify({'error': '缺少图像数据'}), 400
        
        # 获取请求参数
        image_base64 = data['image']
        model_name = data.get('model', None)  # 如果指定了模型，会在service.detect中处理
        confidence_threshold = data.get('confidence_threshold', None)
        
        # 处理base64图像
        try:
            # 移除可能的前缀
            if image_base64.startswith('data:image/'):
                image_base64 = image_base64.split(',')[1]
            
            # 解码base64
            image_data = base64.b64decode(image_base64)
            image = Image.open(io.BytesIO(image_data))
            
            # 转换为numpy数组
            image_np = np.array(image)
            
            if image_np.ndim != 3:
                # 如果是灰度图，转换为RGB
                image_np = np.stack((image_np,) * 3, axis=-1)
        except Exception as e:
            logger.error(f"图像处理失败: {str(e)}")
            return jsonify({'error': '图像处理失败，请检查图像格式'}), 400
        
        # 获取检测服务
        service = get_detection_service()
        
        # 应用临时配置（如果提供）
        temp_config = {}
        if confidence_threshold is not None:
            temp_config['confidence_threshold'] = confidence_threshold
        
        # 执行检测
        start_time = time.time()
        results = service.detect(image_np, model_name=model_name, **temp_config)
        process_time = time.time() - start_time
        
        # 格式化结果
        formatted_results = {
            'detections': results.get('detections', []),
            'performance': {
                'inference_time_ms': process_time * 1000,
                'fps': 1.0 / process_time if process_time > 0 else 0
            },
            'metadata': {
                'image_shape': image_np.shape,
                'model_used': results.get('model_used'),
                'timestamp': time.time()
            }
        }
        
        logger.info(f"图像检测完成，找到 {len(results.get('detections', []))} 个目标")
        return jsonify(formatted_results)
        
    except Exception as e:
        logger.error(f"图像检测失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': f'检测处理失败: {str(e)}'}), 500

# 文件上传检测接口
@detections_bp.route('/upload', methods=['POST'])
def detect_upload():
    """
    文件上传检测接口
    支持直接上传图像文件进行检测
    """
    try:
        # 检查是否有文件
        if 'file' not in request.files:
            return jsonify({'error': '未提供图像文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'error': '未选择文件'}), 400
        
        # 获取其他参数
        model_name = request.form.get('model', None)
        confidence_threshold = request.form.get('confidence_threshold', None)
        if confidence_threshold is not None:
            confidence_threshold = float(confidence_threshold)
        
        # 检查文件类型
        allowed_extensions = {'png', 'jpg', 'jpeg', 'gif'}
        if '.' not in file.filename or \
           file.filename.rsplit('.', 1)[1].lower() not in allowed_extensions:
            return jsonify({'error': '不支持的文件类型，仅支持图片格式'}), 400
        
        # 读取图像
        try:
            image = Image.open(file.stream)
            image_np = np.array(image)
            
            if image_np.ndim != 3:
                # 如果是灰度图，转换为RGB
                image_np = np.stack((image_np,) * 3, axis=-1)
        except Exception as e:
            logger.error(f"文件图像处理失败: {str(e)}")
            return jsonify({'error': '图像处理失败，请检查文件是否为有效图像'}), 400
        
        # 获取检测服务
        service = get_detection_service()
        
        # 应用临时配置
        temp_config = {}
        if confidence_threshold is not None:
            temp_config['confidence_threshold'] = confidence_threshold
        
        # 执行检测
        start_time = time.time()
        results = service.detect(image_np, model_name=model_name, **temp_config)
        process_time = time.time() - start_time
        
        # 格式化结果
        formatted_results = {
            'detections': results.get('detections', []),
            'performance': {
                'inference_time_ms': process_time * 1000,
                'fps': 1.0 / process_time if process_time > 0 else 0
            },
            'metadata': {
                'filename': file.filename,
                'image_shape': image_np.shape,
                'model_used': results.get('model_used'),
                'timestamp': time.time()
            }
        }
        
        logger.info(f"文件上传检测完成，文件名: {file.filename}，找到 {len(results.get('detections', []))} 个目标")
        return jsonify(formatted_results)
        
    except Exception as e:
        logger.error(f"文件上传检测失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': f'检测处理失败: {str(e)}'}), 500

# 批量检测接口
@detections_bp.route('/batch', methods=['POST'])
@token_required
def batch_detect():
    """
    批量图像检测接口
    支持同时检测多张图像
    """
    try:
        data = request.json
        if not data or 'images' not in data:
            return jsonify({'error': '缺少图像数据列表'}), 400
        
        images_data = data['images']
        if not isinstance(images_data, list):
            return jsonify({'error': 'images必须是列表格式'}), 400
        
        if len(images_data) > 10:  # 限制批量检测数量
            return jsonify({'error': '批量检测数量不能超过10张'}), 400
        
        # 获取共享参数
        model_name = data.get('model', None)
        confidence_threshold = data.get('confidence_threshold', None)
        
        # 处理每张图像
        batch_results = []
        service = get_detection_service()
        temp_config = {}
        if confidence_threshold is not None:
            temp_config['confidence_threshold'] = confidence_threshold
        
        for idx, image_item in enumerate(images_data):
            try:
                # 处理base64图像
                image_base64 = image_item.get('image')
                if not image_base64:
                    batch_results.append({'error': '缺少图像数据', 'index': idx})
                    continue
                
                # 移除可能的前缀
                if image_base64.startswith('data:image/'):
                    image_base64 = image_base64.split(',')[1]
                
                # 解码base64
                image_data = base64.b64decode(image_base64)
                image = Image.open(io.BytesIO(image_data))
                image_np = np.array(image)
                
                if image_np.ndim != 3:
                    image_np = np.stack((image_np,) * 3, axis=-1)
                
                # 执行检测
                results = service.detect(image_np, model_name=model_name, **temp_config)
                
                batch_results.append({
                    'index': idx,
                    'detections': results.get('detections', []),
                    'model_used': results.get('model_used')
                })
                
            except Exception as e:
                logger.error(f"批量检测第{idx}张图像失败: {str(e)}")
                batch_results.append({'error': str(e), 'index': idx})
        
        logger.info(f"批量检测完成，总数: {len(images_data)}, 成功: {sum(1 for r in batch_results if 'error' not in r)}")
        return jsonify({
            'batch_size': len(images_data),
            'results': batch_results,
            'timestamp': time.time()
        })
        
    except Exception as e:
        logger.error(f"批量检测失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': f'批量处理失败: {str(e)}'}), 500

# 模型管理接口
@detections_bp.route('/models', methods=['GET'])
def get_models():
    """
    获取已加载的模型列表
    """
    try:
        service = get_detection_service()
        models_info = service.get_loaded_models()
        
        return jsonify({
            'models': models_info,
            'active_model': service.get_active_model_name(),
            'timestamp': time.time()
        })
        
    except Exception as e:
        logger.error(f"获取模型列表失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

@detections_bp.route('/models/<string:model_name>/activate', methods=['POST'])
@token_required
def activate_model(model_name):
    """
    激活指定模型
    """
    try:
        service = get_detection_service()
        success = service.set_active_model(model_name)
        
        if success:
            logger.info(f"模型已激活: {model_name}")
            return jsonify({
                'status': 'success',
                'message': f'模型 {model_name} 已成功激活',
                'active_model': model_name
            })
        else:
            logger.warning(f"激活模型失败: 找不到模型 {model_name}")
            return jsonify({'error': f'找不到模型: {model_name}'}), 404
            
    except Exception as e:
        logger.error(f"激活模型失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

@detections_bp.route('/models/<string:model_name>/load', methods=['POST'])
@token_required
def load_model(model_name):
    """
    加载新模型
    """
    try:
        data = request.json or {}
        model_path = data.get('path')
        device = data.get('device', None)
        
        if not model_path:
            return jsonify({'error': '缺少模型路径'}), 400
        
        # 验证路径
        if not os.path.exists(model_path):
            # 尝试使用相对路径（相对于配置中的模型目录）
            models_dir = get_config('models.directory', './models')
            if not os.path.isabs(model_path):
                model_path = os.path.join(models_dir, model_path)
            
            if not os.path.exists(model_path):
                return jsonify({'error': f'模型文件不存在: {model_path}'}), 404
        
        service = get_detection_service()
        success = service.load_model(model_name, model_path, device=device)
        
        if success:
            logger.info(f"模型已加载: {model_name}, 路径: {model_path}")
            return jsonify({
                'status': 'success',
                'message': f'模型 {model_name} 已成功加载',
                'model_path': model_path
            })
        else:
            logger.error(f"加载模型失败: {model_name}")
            return jsonify({'error': '模型加载失败，请检查模型文件和参数'}), 400
            
    except Exception as e:
        logger.error(f"加载模型失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': str(e)}), 500

@detections_bp.route('/models/<string:model_name>/unload', methods=['POST'])
@token_required
def unload_model(model_name):
    """
    卸载指定模型
    """
    try:
        service = get_detection_service()
        success = service.unload_model(model_name)
        
        if success:
            logger.info(f"模型已卸载: {model_name}")
            return jsonify({
                'status': 'success',
                'message': f'模型 {model_name} 已成功卸载'
            })
        else:
            logger.warning(f"卸载模型失败: 找不到模型 {model_name}")
            return jsonify({'error': f'找不到模型: {model_name}'}), 404
            
    except Exception as e:
        logger.error(f"卸载模型失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

# 检测配置管理
@detections_bp.route('/config', methods=['GET'])
def get_detection_config():
    """
    获取当前检测配置
    """
    try:
        config = get_config('detection', {})
        return jsonify({
            'config': config,
            'timestamp': time.time()
        })
        
    except Exception as e:
        logger.error(f"获取检测配置失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

@detections_bp.route('/config', methods=['PUT'])
@token_required
def update_detection_config():
    """
    更新检测配置
    """
    try:
        data = request.json
        if not data:
            return jsonify({'error': '缺少配置数据'}), 400
        
        # 更新配置
        for key, value in data.items():
            set_config(f'detection.{key}', value)
        
        # 重新加载检测服务配置
        service = get_detection_service()
        service.update_config()
        
        logger.info(f"检测配置已更新: {data.keys()}")
        return jsonify({
            'status': 'success',
            'message': '检测配置已成功更新',
            'updated_keys': list(data.keys())
        })
        
    except Exception as e:
        logger.error(f"更新检测配置失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

# 性能统计接口
@detections_bp.route('/performance', methods=['GET'])
def get_performance_stats():
    """
    获取检测性能统计信息
    """
    try:
        service = get_detection_service()
        performance = service.get_performance_metrics()
        
        return jsonify({
            'performance': performance,
            'timestamp': time.time()
        })
        
    except Exception as e:
        logger.error(f"获取性能统计失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

# 检测服务控制接口
@detections_bp.route('/reload', methods=['POST'])
@token_required
def reload_detection_service():
    """
    重新加载检测服务
    """
    try:
        global _detection_service
        
        # 关闭当前服务
        if _detection_service:
            try:
                _detection_service.shutdown()
                logger.info("检测服务已关闭")
            except Exception as e:
                logger.error(f"关闭检测服务时出错: {str(e)}")
        
        # 重新创建服务实例
        _detection_service = DetectionService()
        logger.info("检测服务已重新加载")
        
        return jsonify({
            'status': 'success',
            'message': '检测服务已成功重新加载'
        })
        
    except Exception as e:
        logger.error(f"重新加载检测服务失败: {str(e)}")
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': str(e)}), 500

@detections_bp.route('/status', methods=['GET'])
def get_detection_status():
    """
    获取检测服务详细状态
    """
    try:
        service = get_detection_service()
        status = service.get_status()
        
        return jsonify({
            'status': status,
            'timestamp': time.time()
        })
        
    except Exception as e:
        logger.error(f"获取检测状态失败: {str(e)}")
        return jsonify({'error': str(e)}), 500

# 导出Blueprint
__all__ = ['detections_bp']